<?php

/**
 * \file
 * Classe `Configurable`.
 *
 * \since 09/03/2009
 * \author Matthieu OVIEDO <matthieu.oviedo@gmail.com> 
 */

/**
 * Classes configurables.
 */ 
namespace pilar\Configurables /* \cond */ ; /* \endcond */
{

/**
 * Instances de classes construites à partir d'options de
 * configuration.
 *
 * L'objectif de cette classe est de permettre la construction
 * d'instances en fournissant des paramètres au constructeur
 * dans un ordre quelconque.
 * 
 * Le processus d'instanciation a été formalisé suivant deux phases.
 *
 * La première phase est une phase de configuration durant laquelle
 * les paramètres de l'instance sont modifiés par définition et
 * changement de valeur. A l'issue de cette étape les paramètres
 * ne peuvent plus être modifiés, ils sont néanmoins accessibles
 * en lecture seule tant que l'instance n'est pas détruite.
 *
 * La deuxième étape est la phase d'initialisation de la nouvelle
 * instance à partir de la configuration précédemment établie.
 *
 * \since 09/03/2009
 * \author Matthieu OVIEDO <matthieu.oviedo@gmail.com>
 */
abstract class Configurable {

/**
 * Collection de paramètres associés à la classe.
 *
 * \since 09/03/09
 * \author Matthieu OVIEDO <matthieu.oviedo@gmail.com> 
 */
private $_params;


/**
 * Utilisé pour assurer la bonne configuration de la classe.
 *
 * Le constructeur l'utilise pour vérifier que la chaîne des appels
 * de la méthode \a loadDefaultParams() ne soit pas interrompue par
 * l'oubli d'un appel à \a parent::loadDefaultParams() .
 *
 * \see loadDefaultParams
 *
 * \since 09/03/2009
 * \author Matthieu OVIEDO <matthieu.oviedo@gmail.com> 
 */
private $_defaultParamsLoaded = false;


/**
 * Utilisé pour assurer la bonne reconfiguration de la classe.
 *
 * Même principe de fonctionnement que pour \a $_defaultParamsLoaded .
 *
 * \see overwriteParams
 * \see loadDefaultParams
 *
 * \since 09/03/2009
 * \author Matthieu OVIEDO <matthieu.oviedo@gmail.com> 
 */
private $_paramsOverwritten = false;


/**
 * Utilisé pour assurer la bonne initialisation de la classe.
 *
 * Même principe de fonctionnement que pour \a $_defaultParamsLoaded .
 *
 * \see _initialize
 * \see loadDefaultParams
 *
 * \since 09/03/2009
 * \author Matthieu OVIEDO <matthieu.oviedo@gmail.com> 
 */
private $_initialized = false;


/**
 * Constructeur générique.
 * 
 * \param $params Paramètres de configuration à appliquer à
 *                l'instance.
 *
 * \since 09/03/2009
 * \author Matthieu OVIEDO <matthieu.oviedo@gmail.com> 
 */
final public function __construct($params = null) {
 // Allocation de la la collection de paramètres associée
 // à la configuration de la classe :
  $this->_params = new \pilar\ParamCollections\Collection();

 // Chargement des paramètres :
  // Valeurs par défaut issues des classes déscendantes :
   $this->loadDefaultParams();
   // TODO : Vérifier la bonne configuration de l'instance.
  // Valeurs passées en argument du constructeur de l'instance
  // courante :
   if($params != null) $this->_params->set($params);
  // Reconfiguration pour traitement des cas pathologiques et
  // application de contraintes sur les paramètres :
   $this->overwriteParams();
   // TODO : Vérifier la bonne reconfiguration de l'instance.
  
 // Initialisation de l'instance :
  $this->initialize();
}


/**
 * Dédiée à la définition de nouveaux paramètres et à l'attribution
 * de valeurs par défaut sur les paramètres issus des classes
 * supérieures.
 *
 * Cette étape est la seule étape dans laquelle il est possible de
 * définir des nouveaux paramètres de configuration pour la classe.
 *
 * Toute classe de la déscendance surchargeant la méthode doit
 * obligatoirement faire appel à la méthode \a loadDefaultParams() de sa
 * classe parente.
 *
 * \since 09/03/2009
 * \author Matthieu OVIEDO <matthieu.oviedo@gmail.com> 
 */
protected function loadDefaultParams() {
 // Dans la mesure où les appels récursifs sont bien remontés
 // jusqu'à ici on peut supposer que la configuration
 // s'est bien déroulée :
  $this->_defaultParamsLoaded= true;
}


/**
 * Dédiée au traitement du cas pathologique de l'initialisation
 * de paramètres inter-dépendants.
 *
 * Le besoin se fait ressentir lorsque l'on souhaite
 * attribuer à un paramètre, qui par exemple aurait la valeur \c NULL,
 * une valeur par défaut dépendant des valeurs d'autres paramètres.
 *
 * Dans cette étape il est donc encore possible de changer la valeur
 * de paramètres mais il n'est par contre plus possible de définir
 * de nouveaux paramètres.
 *
 * Toute classe de la déscendance surchargeant la méthode doit
 * obligatoirement faire appel à la méthode \a overwriteParams()
 * de sa classe parente.
 *
 * \since 09/03/2009
 * \author Matthieu OVIEDO <matthieu.oviedo@gmail.com> 
 */
protected function overwriteParams() {
 // Dans la mesure où les appels récursifs sont bien remontés
 // jusqu'à ici on peut supposer que la configuration
 // s'est bien déroulée :
  $this->_paramsOverwritten = true;
}


/**
 * Fonction d'initialisation de l'instance.
 *
 * Toute classe de la déscendance surchargeant la méthode doit
 * obligatoirement faire appel à la méthode \a _reconfigure()
 * de sa classe parente.
 *
 * \since 09/03/2009
 * \author Matthieu OVIEDO <matthieu.oviedo@gmail.com> 
 */
protected function initialize() {
 // Dans la mesure où les appels récursifs sont bien remontés
 // jusqu'à ici on peut supposer que la configuration
 // s'est bien déroulée :
  $this->_initialized = true;
}


/**
 * Définit de nouveaux paramètres.
 *
 * Un paramètre définit par une classe ancêtre ne peut être
 * reféfinit.
 *
 * \param $params Tableau associatif { $nom => $valeurParDefaut } des
 *                paramètres à définir.
 *
 * \since 09/03/2009
 * \author Matthieu OVIEDO <matthieu.oviedo@gmail.com> 
 */
final public function defineParams($params) {
 if ($this->_defaultParamsLoaded) {
  // A partir du moment où l'instance a été configurée il
  // n'est plus possible de définir de nouveaux paramètres :
   // TODO : Générer une erreur.
 }
 return $this->_params->define($params);
}


/**
 * Modifie les valeurs d'un ensemble de paramètres.
 *
 * \param $params Tableau associatif { $nom => $valeur } des
 *                paramètres à modifier.
 *
 * \since 09/03/2009
 * \author Matthieu OVIEDO <matthieu.oviedo@gmail.com> 
 */
final public function setParams($params) {
 if ($this->_paramsOverwritten) {
  // A partir du moment où l'instance a été reconfigurée il
  // n'est plus possible de changer les valeurs des
  // paramètres :
   // TODO : Générer une erreur.
 }
 return $this->_params->set($params);
}


/**
 * Retourne la valeur d'un paramètre.
 *
 * \param $name Nom du paramètre.
 * \return Valeur du paramètre.
 *
 * \since 09/03/2009
 * \author Matthieu OVIEDO <matthieu.oviedo@gmail.com> 
 */
final public function param($name) {
 return $this->_params->get($name);
}


} // Class.

} // Namespace.

?>
